package com.ideal.manage.esms.service.esms;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ideal.manage.esms.bean.diagnostic.DiagnoseResultInfo;
import com.ideal.manage.esms.bean.project.*;
import com.ideal.manage.esms.jpa.JpaRepositoryImpl;
import com.ideal.manage.esms.service.diagnostic.DiagnoseResultInfoService;
import com.ideal.manage.esms.service.project.EquipmentManageService;
import com.ideal.manage.esms.service.project.ProjectManageService;
import com.ideal.manage.esms.util.DBUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * Created by 83730 on 2018/6/12.
 */
@Service
@Transactional
public class EsmsService {

    private Logger logger = LoggerFactory.getLogger(EsmsService.class);

    @Resource
    private DiagnoseResultInfoService diagnoseResultInfoService;
    @Resource
    private ProjectManageService projectManageService;
    @Resource
    private EquipmentManageService equipmentManageService;

    @Autowired
    private TransportClient transportClient;

    @Autowired
    private EntityManager entityManager;

    private JpaRepositoryImpl<ParameterInfo, String> parameterJpaRepository;
    private JpaRepositoryImpl<EquipmentManage, String> equipmentManageJpaRepository;
    private JpaRepositoryImpl<DiagnoseResultInfo, String> diagnoseResultInfoJpaRepository;
    private JpaRepositoryImpl<ProjectManage, String> projectManageJpaRepository;

    @PostConstruct
    public void init() {
        this.parameterJpaRepository = new JpaRepositoryImpl<>(ParameterInfo.class, entityManager);
        this.equipmentManageJpaRepository = new JpaRepositoryImpl<>(EquipmentManage.class, entityManager);
        this.diagnoseResultInfoJpaRepository = new JpaRepositoryImpl<>(DiagnoseResultInfo.class, entityManager);
        this.projectManageJpaRepository = new JpaRepositoryImpl<ProjectManage, String>(ProjectManage.class, entityManager);
    }

    protected EquipmentManage queryEquipmentManage(String esName, String macId, String ip) {
        ParameterInfo parameterInfo = parameterJpaRepository.findOne(QParameterInfo.parameterInfo.esName.eq(esName));
        if (parameterInfo == null) {
            return null;
        }
        QEquipmentManage qEquipmentManage = QEquipmentManage.equipmentManage;
        if (parameterInfo.getObjName().equals(ParameterInfo.OBJECT_NAME_PROJECT) ||
                parameterInfo.getObjName().equals(ParameterInfo.OBJECT_NAME_BATTERY_PACK) ||
                parameterInfo.getObjName().equals(ParameterInfo.OBJECT_NAME_CONVERTER)) {
            return equipmentManageJpaRepository.findOne(qEquipmentManage.code.eq(macId)
                    .and(qEquipmentManage.project.ip.eq(ip)));
        } else {
            //中文匹配
            String t[] = esName.split("_");
            if (t.length < 2) {
                return null;
            }
            String eqName = NumberUtils.toInt(t[1], 0) + "#" +
                    (parameterInfo.getObjName().equals(ParameterInfo.OBJECT_NAME_BATTERY) ? "电池单体" : "电池模组");
            return equipmentManageJpaRepository.findOne(qEquipmentManage.equipmentType.in("3", "4")
                    .and(qEquipmentManage.project.id.eq(ip))
                    .and(qEquipmentManage.name.eq(eqName)));
        }
    }


    /**
     * 接口1获取最新一次的数据
     *
     * @param type
     * @param data
     * @return
     */
    public JSONArray findDataPython1(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String ip = jsonObject.getString("ip");
        String port = jsonObject.getString("port");
        String macid = jsonObject.getString("macid");
        long time = jsonObject.getLong("time");

        EquipmentManage equipmentManage = equipmentManageService.findOneByCode(macid);
        Date date = diagnoseResultInfoService.findLastedDate(equipmentManage.getId());
        JSONObject result = new JSONObject();
        //获取最新一次的数据
        List<DiagnoseResultInfo> list = diagnoseResultInfoService.findLastedData(equipmentManage.getId(), date);
        for (DiagnoseResultInfo diagnoseResultInfo : list) {
            String key = diagnoseResultInfo.getSetVal();
            if ("soc".equals(key) || "dcbrl".equals(key) || "kccdl".equals(key) || "xhcs".equals(key)
                    || key.startsWith("dtsoc_") || key.startsWith("dtzz_") || key.startsWith("dtrl_")) {
                result.put(key, Double.parseDouble(diagnoseResultInfo.getResultVal()));
                result.put("time", diagnoseResultInfo.getCreateTime().getTime());
                result.put("ip", ip);
                result.put("port", port);
                result.put("macid", macid);
            }
        }

        JSONArray jsonArray = new JSONArray();

        jsonArray.add(result);
        return jsonArray;
    }

    /**
     * 接口数据入库
     *
     * @param data
     */
    public void savePython1(String data) {
        List<String> keys = Arrays.asList("soc", "kcxdl", "kccdl", "xhcs", "dczlsd", "socbzc",
                "socfc", "socqwz", "socbyxs", "socsfwsql", "socsfwsqm", "socsfwsqu",
                "socsfwsc", "socyzx", "dtrlbzc", "dtrlfc", "dtrlqwz", "dtrlbyxs", "dtrlsfwsql",
                "dtrlsfwsqm", "dtrlsfwsqu", "dtrlsfwsc", "dtrlyzx", "dtsocbzc", "dtsocfc", "dtsocqwz",
                "dtsocbyxs", "dtsocsfwsql", "dtsocsfwsqm", "dtsocsfwsqu", "dtsocsfwsc", "dtsocyzx", "dtzzbzc",
                "dtzzfc", "dtzzqwz", "dtzzbyxs", "dtzzsfwsql", "dtzzsfwsqm", "dtzzsfwsqu", "dtzzsfwsc", "dtzzyzx",
                "dtdybzc", "dtdyfc", "dtdyqwz", "dtdybyxs", "dtdysfwsql", "dtdysfwsqm", "dtdysfwsqu", "dtdysfwsc",
                "dtdyyzx", "dlbzc", "dlfc", "dlqwz", "dlbyxs", "dlsfwsql", "dlsfwsqm", "dlsfwsqu", "dlsfwsc", "dlyzx", "wdbzc",
                "wdfc", "wdqwz", "wdbyxs", "wdsfwsql", "wdsfwsqm", "wdsfwsqu", "wdsfwsc", "wdyzx");
        JSONObject jsonObject = JSONObject.parseObject(data);
        String macid = jsonObject.getString("macid");
        saveDiagnoseResultInfo(macid, jsonObject, keys::contains);
    }

    /**
     * 入库操作
     *
     * @param macid
     * @param data
     */
    protected void saveDiagnoseResultInfo(String macid, JSONObject data, MatchFunction func) {
    }

    /**
     * 接口2查询时段数据
     *
     * @param type
     * @param data
     * @return
     */
    public JSONArray findDataPython2(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String ip = jsonObject.getString("ip");
        String port = jsonObject.getString("port");
        String macid = jsonObject.getString("macid");
        String cycle = jsonObject.getString("cycle");
        String time = jsonObject.getString("time");

        Long value = Long.valueOf(cycle) * 1000;
        Long startTime = Long.valueOf(time) - value;
        Long endTime = Long.valueOf(time);
        SearchRequestBuilder prepareSearch = transportClient.prepareSearch();
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("ip", ip))
                .filter(QueryBuilders.termQuery("macid", macid))
                .filter(QueryBuilders.rangeQuery("time").gte(startTime).lt(endTime)));

        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        JSONArray r = new JSONArray();
        if (searchResponse.getHits().getHits().length == 0) {
            return r;
        }
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            JSONObject json = new JSONObject();
            json.put("ip", ip);
            json.put("port", port);
            json.put("macid", macid);
            json.put("time", time);
            Map<String, Object> map = hit.getSourceAsMap();
            for (String key : map.keySet()) {
                if (key.equals("BatCurrent") || (key.startsWith("Cell_") && key.endsWith("_Volt")) ||
                        (key.startsWith("Cell_") || key.endsWith("_Temp"))) {
                    json.put(key, map.get(key));
                }
            }
            r.add(json);
        }
        return r;
    }

    public void savePython2(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String macid = jsonObject.getString("macid");
        saveDiagnoseResultInfo(macid, jsonObject, key -> key.startsWith("wdad_") || key.equals("dlad")
                || key.startsWith("dtsoc_") || key.startsWith("dtzzad_") || key.startsWith("dtrlad_"));
    }

    /**
     * 接口3获取一个月的数据
     *
     * @param type
     * @param data
     * @return
     */
    public JSONArray findDataPython3(Long type, String data) {
        JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject = JSONObject.parseObject(data);
        String ip = jsonObject.getString("ip");
        String port = jsonObject.getString("port");
        String macid = jsonObject.getString("macid");
        String time = jsonObject.getString("time");
        Long value = 30 * 24 * 3600 * 1000L;//1个月

        Long endTime = Long.parseLong(time);
        Long startTime = endTime - value;
        //开始时间
        Date startDate = new Date();
        startDate.setTime(startTime);
        //结束时间
        Date endDate = new Date();
        endDate.setTime(endTime);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String start = sdf.format(startDate);//将时间格式转换成符合Timestamp要求的格式.
        String end = sdf.format(endDate);

        Connection conn = null;
        String sql;
        PreparedStatement preStmt = null;
        ResultSet rs = null;
        List<Timestamp> list = new ArrayList<>();

        conn = DBUtils.getConnection();
        try {
            sql = "select DISTINCT (create_time) from esms_diagnose_result_info " +
                    "where create_time BETWEEN '" + start + "' and '" + end + "' order by create_time";
            preStmt = conn.prepareStatement(sql);
            logger.debug(sql);
            rs = preStmt.executeQuery();

            while (rs.next()) {
                Timestamp createTime = rs.getTimestamp(1);
                list.add(createTime);
            }

            jsonArray = findData(conn, list, ip, port, macid, type);

        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            DBUtils.dbClose(conn, preStmt, rs);
        }
        return jsonArray;
    }

    private JSONArray findData(Connection conn, List<Timestamp> list, String ip, String port, String macid, Long type) {
        JSONArray jsonArray = new JSONArray();
        if (list.isEmpty()) {
            return jsonArray;
        }
        String sql;
        PreparedStatement preStmt = null;
        ResultSet rs = null;
        try {
            String t = list.stream().map(time -> String.format("'%s'", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time)))
                    .collect(Collectors.joining(","));
            sql = "select set_val,result_val, create_time from esms_diagnose_result_info " +
                    "where create_time IN(" + t + ")";
            preStmt = conn.prepareStatement(sql);
            logger.debug(sql);
            rs = preStmt.executeQuery();

            while (rs.next()) {
                String setVal = rs.getString(1);
                String resultVal = rs.getString(2);
                if ("dlad".equals(setVal) || setVal.startsWith("dtzzad_") || setVal.startsWith("wdad_")
                        || setVal.startsWith("dtrlad_")) {
                    JSONObject result = new JSONObject();
                    result.put("time", rs.getDate(3).getTime());
                    result.put("ip", ip);
                    result.put("port", port);
                    result.put("macid", macid);
                    result.put(setVal, Double.parseDouble(resultVal));
                    jsonArray.add(result);
                }
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return jsonArray;
    }

    public void savePython3(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String macid = jsonObject.getString("macid");
        saveDiagnoseResultInfo(macid, jsonObject, key -> key.startsWith("dtzz_") || key.startsWith("dtrl_"));

    }

    /**
     * 获取一个月的数据
     *
     * @param type
     * @param data
     * @return
     */
    public JSONArray findDataPython4(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String ip = jsonObject.getString("ip");
        String port = jsonObject.getString("port");
        String macid = jsonObject.getString("macid");
        String time = jsonObject.getString("time");

        JSONArray array = new JSONArray();
        Long value = 2 * 60 * 600 * 1000L;//2小时
        Long startTime = Long.valueOf(time) - value;
        Long endTime = Long.valueOf(time);
        SearchHit[] hits = getPython4BatCurrent(startTime, endTime, ip, macid);
        if (hits == null || hits.length == 0) {
            return array;
        }

        SearchRequestBuilder prepareSearch = transportClient.prepareSearch();
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.termQuery("macid", macid))
                .must(QueryBuilders.rangeQuery("time").gte(startTime).lt(endTime)));

        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit cellHits[] = searchResponse.getHits().getHits();
        int size = Math.min(hits.length, cellHits.length);
        for (int i = 0; i < size; i++) {
            boolean isSet = false;
            JSONObject obj = new JSONObject();
            Map<String, Object> cellMap = cellHits[i].getSourceAsMap();
            for (String key : cellMap.keySet()) {
                if ((key.startsWith("Cell_") || key.endsWith("_Volt"))) {
                    obj.put(key, cellMap.get(key));
                    isSet = true;
                }
            }
            if (isSet) {
                obj.put("BatCurrent", hits[i].getSourceAsMap().get("BatCurrent"));
                array.add(obj);
            }
        }
        return array;
    }

    private SearchHit[] getPython4BatCurrent(long startTime, long endTime, String ip, String macid) {
        SearchRequestBuilder prepareSearch = transportClient.prepareSearch();
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.termQuery("macid", macid))
                .must(QueryBuilders.rangeQuery("time").gte(startTime).lt(endTime))
                .must(QueryBuilders.existsQuery("BatCurrent")));
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        return searchResponse.getHits().getHits();
    }

    public void savePython4(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String macid = jsonObject.getString("macid");
        saveDiagnoseResultInfo(macid, jsonObject, key -> key.equals("dcbrl"));
    }

    /**
     * 获取实时的数据
     *
     * @param type
     * @param data
     * @return
     */
    public JSONArray findDataPython5(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);

        SearchHit searchMax = getPython5ByName(jsonObject, "MaxAllwChrgCurr");
        SearchHit searchChr = getPython5ByName(jsonObject, "ChrgReqCurr");
        SearchHit oct = getPython5ByName(jsonObject, "CHRG_OCT");
        JSONObject r = new JSONObject();
        if (searchMax != null) {
            r.put("MaxAllwChrgCurr", searchMax.getSourceAsMap().get("MaxAllwChrgCurr"));
        }
        if (searchChr != null) {
            r.put("ChrgReqCurr", searchChr.getSourceAsMap().get("ChrgReqCurr"));
        }
        if (oct != null) {
            Map<String, Object> map = oct.getSourceAsMap();
            for (String key : map.keySet()) {
                if (key.equals("DSCH_OCT") || key.equals("CHRG_OCT")
                        || key.equals("DSCH_OCS") || key.equals("CHRG_OCS")) {
                    r.put(key, map.get(key));
                }
            }
        }
        JSONArray a = new JSONArray();
        a.add(r);
        return a;
    }

    protected SearchHit getPython5ByName(JSONObject jsonObject, String name) {
        String ip = jsonObject.getString("ip");
        String macid = jsonObject.getString("macid");

        SearchRequestBuilder prepareSearch = transportClient.prepareSearch();
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.termQuery("macid", macid))
                .should(QueryBuilders.existsQuery(name)));
        prepareSearch.addSort(SortBuilders.fieldSort("time").order(SortOrder.DESC));
        prepareSearch.setSize(1);

        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit hits[] = searchResponse.getHits().getHits();
        if (hits.length == 0) {
            return null;
        }
        return hits[0];
    }

    public void savePython5(Long type, String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String macid = jsonObject.getString("macid");
        saveDiagnoseResultInfo(macid, jsonObject, key -> key.equals("zdyxcddl") || key.equals("cddlqqz")
                || key.equals("stfddl") || key.equals("stcddl") || key.equals("wtfddl") || key.equals("wtcddl"));
    }

    interface MatchFunction {
        public boolean isMatch(String name);
    }

}
